package com.kim.store.contorller;

import com.kim.store.contorller.ex.*;
import com.kim.store.entity.User;
import com.kim.store.service.IUserService;
import com.kim.store.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @RestController 等于 @ResponseBody + @Controller
 * @ResponseBody:表示此方法的响应结果以json格式进行数据响应到前端
 * @RequestBody:主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)；
 * @RequestParam 是从request里面拿取值。
 * @PathVariable 是从一个URI模板里面来填充。
 *
 * http://localhost:8080/springmvc/hello/101?param1=10&param2=20
 * public String getDetails(
 *  @RequestParam(value="param1", required=true) String param1,
 *  @RequestParam(value="param2", required=false) String param2){
 * ...
 * }
 */

@RestController
@RequestMapping("/user")
public class UserController extends BaseController{
    @Autowired
    private IUserService userService;

    /*
    @RequestMapping("/reg")
    //@RequestBody //表示此方法的响应结果以Json格式进行数据的响应给到前端
    public JsonResult<Void> reg(User user){
        //创建响应结果对象
        JsonResult<Void> result = new JsonResult<>();
        try {
            userService.reg(user);
            result.setState(200);
            result.setMessage("用户注册成功");
        } catch (UsernameDuplicatedException e) {
            result.setState(4000);
            result.setMessage("用户名被占用");
        }catch (InsertException e1){
            result.setState(5000);
            result.setMessage("注册时产生未知异常");
        }
        return result;
    }
     */

    /**
     * 为什么Springboot能够用这两种方法接收前端数据？
     * 约定大于配置：开发思想来完成，省略掉大量的配置甚至注解的编写
     *
     * 控制层如何接收前端的数据
     * 方法一.接收数据的方式：请求处理方法的参数列表设置为pojo类型来接收前端的数据
     *   springboot会将前端的url地址中的参数名和pojo类的属性名进行比较，如果
     *   这两个名称相同，则将值注入到pojo类中对应的属性上
     */
    @RequestMapping("/reg")
    //@RequestBody //表示此方法的响应结果以Json格式进行数据的响应给到前端
    public JsonResult<Void> reg(User user){
        //创建响应结果对象
        userService.reg(user);
        return new JsonResult<>(OK);
    }

    /**
     * 控制层如何接收前端的数据
     * 方法二.接收数据的方式：请求处理方法的参数类型设置为非pojo类型(如:String)
     *   springboot会直接将请求的参数名和方法的参数名直接进行比较，如果
     *   名称相同则自动完成值的依赖注入
     *
     *
     */
    @RequestMapping("/login")
    public JsonResult<User> login(String username, String password,HttpSession session){
        User data = userService.login(username, password);
        /**
         * 服务器本身在启动时自动创建session对象，这已经是一个全局的session对象。
         * springboot直接使用session对象，直接将HttpSession类型的对象作为请求处理方法的参数，
         * 会自动将全局的session对象注入到请求处理方法的session形参上
         */
        //向session对象中完成数据的绑定(session全局的)
        session.setAttribute("uid",data.getUid());
        session.setAttribute("username",data.getUsername());
        //获取session中绑定的数据
        System.out.println(getUidFromSession(session));
        System.out.println(getUsernameFromSession(session));

        //String upload = session.getServletContext().getRealPath("upload");
       // System.out.println(upload);

        return new JsonResult<User>(OK,data);
    }

    @RequestMapping("/change_password")
    public JsonResult<Void> changePassword(String oldPassword,String newPassword,HttpSession session){
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        userService.changePassword(uid,username,oldPassword,newPassword);
        return new JsonResult<>(OK);
    }

    @RequestMapping("/get_by_uid")
    public JsonResult<User> getById(HttpSession session){
        User data = userService.getByUid(getUidFromSession(session));
        return new JsonResult<>(OK,data);
    }

    @RequestMapping("/change_info")
    public JsonResult<Void> changeInfo(User user,HttpSession session){
        //user对象中有四部分的数据username、phone、email、gender
        //uid数据需要再次封装到user对象中
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        userService.changeInfo(uid,username,user);
        return new JsonResult<>(OK);
    }

    /**
     * MultipartFile接口：是SpringMVC提供的接口，
     * 这个接口为我们包装了获取文件类型的数据(任何类型的file都可以接收)
     * SpringBoot它整合了SpringMVC,只需要在处理请求的方法参数列表上
     * 声明一个参数类型为MultipartFile的参数，然后springboot自动将传递给服务器的文件数据
     * 赋值给这个参数
     *
     * @RequestParam：表示请求中的参数，将请求中的参数注入请求处理方法的某个参数上
     * 如果名称不一致则可以使用@RequestParam注解进行标记和映射
     *
     * @param session
     * @param file
     * @return
     */
    //设置上传文件的最大值
    public static final int AVATAR_MAX_SIZE = 10*1024*1024;
    //限制上传文件的类型
    public static final List<String> AVATAR_TYPE = new ArrayList<>();
    static {
        //初始化集合
        AVATAR_TYPE.add("image/jpeg");
        AVATAR_TYPE.add("image/png");
        AVATAR_TYPE.add("image/bmp");
        AVATAR_TYPE.add("image/gif");
    }

    @RequestMapping("/change_avatar")
    public JsonResult<String> changeAvatar(HttpSession session,
                                           @RequestParam("file") MultipartFile file){
        //文件是否为null
        if (file.isEmpty()){
            throw new FileEmptyException("文件为空");
        }
        if (file.getSize()>AVATAR_MAX_SIZE){
            throw new FileSizeException("文件超出限制");
        }
        //判断文件的类型是否是我们规定的后缀类型
        String contentType = file.getContentType();
        System.out.println("contentType="+contentType);

        if (!(AVATAR_TYPE.contains(contentType))){
            throw new FileTypeException("文件类型不支持");
        }

        /**
         * 如何处理上传头像
         *
         * 1.在本地电脑端创建一个文件夹存放前端传进来的数据
         *
         * 获取上下文的真实绝对路径,由于是获取的是tomcat上下文绝对路径这个路径是临时文件
         * 此路径在c盘占用空间，所以我修改了路径
         *         String parent = session.getServletContext().getRealPath("upload");
         * 但是使用
         * String parent = "D:\\project\\computer-mall-project\\store\\upload";
         * 上传头像后，想要在前端显示头像，就是改变img标签的src属性值，使用相对路径失败！！！
         */

        //上传的文件目录结构 .../upload/文件.png
        //获取上下文的真实绝对路径
        String parent = session.getServletContext().getRealPath("upload");
        //System.out.println("parent="+parent);
        //String parent = "D:\\project\\images\\upload";
        //File对象指向这个路径，File是否存在
        File dir = new File(parent);
        //检测当前目录是否存在
        if (!(dir.exists())){
            //如不存在，创建目录
            dir.mkdirs();
        }
        System.out.println("dir="+dir);

        /**
         * 2.从前端获取照片的名字，并随机重命名照片名字
         */
        //获取到这个文件名称，UUID工具类来生成一个新的字符串作为文件名称
        //getOriginalFilename():只返回文件的名称，不包含文件目录结构
        String originalFilename = file.getOriginalFilename();
        System.out.println("originalFilename= "+ originalFilename);
        //记录最后一个小数点的位置
        int index = originalFilename.lastIndexOf(".");
        //获取文件名的后缀
        String suffix = originalFilename.substring(index);
        //随机生成文件名
        String filename = UUID.randomUUID().toString().toUpperCase() +  suffix;
        //创建一个文件（包含文件名和文件目录结构）
        File dest = new File(dir,filename); //空文件
        /**
         * 3.将从前端得到文件的内容复制到自己电脑文件夹下
         */
        try {
            //参数file中的数据写入到dest这个空文件中
            file.transferTo(dest);
        }catch (FileStateException e){
            throw new FileSizeException("文件状态异常");
        }
        catch (IOException e) {
            throw new FileUploadIOException("文件读写异常");
        }
        int uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        //返回头像的相对路径 /upload/test.png
        /**
         * 4.更新数据库avatar字段
         * avatar字段里面的内容是文件的路径名
         */
        String avatar = "/upload/" + filename;
        userService.changeAvatar(uid,avatar,username);
        //返回用户头像的路径给前端，将来用于头像的展示使用
        /**
         * 5.将文件名返回给JsonResult对象保存
         */
        return new JsonResult<>(OK,avatar);
    }


}
